from typing import List, Final, Tuple, Self
from enum import Enum
import pygame

from game.data.assets.assetManager import load_font,load_audio
from game.sprites.barrier import Barrier, BarrierSimple

class Direction(Enum):
    N = [0, -1]
    NE = [1, -1]
    E = [1, 0]
    SE = [1, 1]
    S = [0, 1]
    SW = [-1, 1]
    W = [-1, 0]
    NW = [-1, -1]
    NONE = [0, 0]
    
    @classmethod
    def isDiagonal(cls, direction) -> bool:
        match direction:
            case cls.N | cls.E | cls.S | cls.W | cls.NONE: return False
            case _ : return True        
    
    @classmethod
    def add(cls, direction1, direction2):

        if direction1 == direction2: return direction1
        
        if cls.isDiagonal(direction1) and cls.isDiagonal(direction2):
            return cls([
                (direction1.value[0] + direction2.value[0]) // 2,
                (direction1.value[1] + direction2.value[1]) // 2
            ])
        
        v0 = direction1.value[0] + direction2.value[0]
        v1 = direction1.value[1] + direction2.value[1]
        
        if (abs(v0) == 2) or (abs(v1) == 2):
            if cls.isDiagonal(direction1): return direction1   
            if cls.isDiagonal(direction2): return direction2
        
        return cls([v0, v1])

    @classmethod
    def sub(cls, direction1, direction2):
        return cls.add(
            direction1,
            cls([-direction2.value[0], -direction2.value[1]])
        )

class CONSTANT:
    """ Store constant values """

    class APP:
        # VIDEO_INFO = pygame.display.Info()
        # RESOLUTION: Final[Tuple[int, int]] = (VIDEO_INFO.current_w, VIDEO_INFO.current_h)
        
        RESOLUTION: Final[Tuple[int, int]] = (1280, 720) # Use 1280x720 for now
        FPS: Final[int] = 60
        CAPTION: Final[str] = 'RPG'

        # Colors
        Black = (0,0,0)
        Red = (255, 0, 0)
        White = (255, 255, 255)
        Blue = (0, 255, 255)
        Yellow = (255, 255, 0)

        BUTTON_FONT = load_font('test/SmileySans-Oblique.ttf', 30)
        # music
        main_menu_music = load_audio('test/Deep Stone Lullaby.mp3')
        game_music1 = load_audio('test/Before Summer.mp3')
        game_music2 = load_audio('test/Gold Cup of Oases.mp3')

        # sound effect
        test_sound_effect = load_audio('test/catastophic_explosion.wav')
    class ENTITY:
        DEFAULT_DIRECTION: Direction = Direction.S

    class PLAYER:
        MAX_INTERACT_RADIUS: Final[float] = 100.0
        
        class BASE:
            HITINTERVAL: Final[int] = 500

            class STAT:
                DAMAGE: Final[int] = 10
                HEALTH: Final[int] = 100
                DEFENSE: Final[int] = 0
                STRENGTH: Final[int] = 0
                INTELLIGENCE: Final[int] = 0
                CRIT_CHANCE: Final[float] = 0
                CRIT_DAMAGE: Final[float] = 0
                BONUS_ATTACK_SPEED: Final[float] = 0
                BONUS_ABILITY_DAMAGE: Final[float] = 0
                BONUS_SPEED: Final[float] = 0
                LUCK: Final[float] = 0.05

            class SPEED:
                SNEAKING_SPEED: Final[float] = 0.35
                WALKING_SPEED: Final[float] = 1
                SPRINTING_SPEED: Final[float] = 1.2

    class WORLD:
        WORLD_LEVEL_MODIFIER: Final[List[float]] = [1, 1.5, 2, 2.5]
        MAX_WORLD_LEVEL_MODIFIER: Final[float] = 2.5


class Variables:
    """ Store game variables """

    world = None 

    screen: pygame.Surface = pygame.display.set_mode(CONSTANT.APP.RESOLUTION) # type: ignore
    clock: pygame.time.Clock = None # type: ignore

    is_full_screen: bool = True
    is_game_paused: bool = True
    is_game_started: bool = False
    current_ui = None
    last_ui = None
    audio_volume = 5  # range: [0, 10]
    
    in_dialog = False
    
    in_editor_mode = False
    editor_pos1 = None
    
    obstacle_group = None
    visible_group = None    

# Editor

EDITOR_MODE = False

sl = []

def draw(pos1, pos2):
    if not EDITOR_MODE: return
    
    sl.append(
        Barrier(pos1, pos2, [Variables.obstacle_group, Variables.visible_group])
    )
    
def back():
    if not EDITOR_MODE: return
    if sl:
        s = sl.pop()
        s.kill()
        
def save():
    if not EDITOR_MODE: return
    fhand = open("save.txt", "a")
    fhand.write("="*10+'\n')
    for s in sl:
        fhand.write(" ".join([str(int(i)) for i in [s.left, s.top, s.right, s.bottom, s.width, s.height]]) + "\n")
    fhand.close()

from pathlib import Path
DIR = Path(__file__).parent.absolute() / "data" / "plot" 

def load():
    if not EDITOR_MODE: return
    fhand = open(DIR / "barrier.txt", "r", encoding='utf8')
    while line:= fhand.readline():
        l = line.split()
        l = [int(item) for item in l]
        
        BarrierSimple(l, [Variables.obstacle_group, Variables.visible_group])
        
def load_barrier():
    fhand = open(DIR / "barrier.txt", "r", encoding='utf8')
    while line:= fhand.readline():
        l = line.split()
        l = [int(item) for item in l]
        
        BarrierSimple(l, [Variables.obstacle_group])